# src/audio_utils.py
# -*- coding: utf-8 -*-
import os
import subprocess
from typing import List

def _escape_single_quotes(p: str) -> str:
    # ffmpeg concat 列表里如果路径含有单引号，需要转义成 '\'' 形式
    return p.replace("'", r"'\''")

def concat_wavs_ffmpeg(wavs: List[str], out_path: str) -> str:
    """
    用 ffmpeg concat 把多段 wav 合并为一个 wav。
    - wavs: 分段音频路径列表（必须非空、都存在、非 0 字节）
    - out_path: 输出路径
    """
    if not wavs:
        raise ValueError("待合并的 wav 列表为空（可能 TTS 未产出）。")

    # 校验文件都存在且非空
    abs_wavs = []
    for w in wavs:
        aw = os.path.abspath(w)
        if not os.path.exists(aw):
            raise FileNotFoundError(f"片段不存在: {aw}")
        if os.path.getsize(aw) == 0:
            raise RuntimeError(f"片段是空文件: {aw}")
        abs_wavs.append(aw)

    os.makedirs(os.path.dirname(out_path), exist_ok=True)
    list_file = out_path + ".list.txt"

    # 写入 concat 列表，必须是：file '绝对路径'
    with open(list_file, "w", encoding="utf-8", newline="\n") as f:
        for aw in abs_wavs:
            esc = _escape_single_quotes(aw)
            f.write(f"file '{esc}'\n")

    cmd = [
        "ffmpeg", "-y",
        "-f", "concat", "-safe", "0",
        "-i", list_file,
        "-c:a", "pcm_s16le",
        out_path
    ]

    try:
        cp = subprocess.run(
            cmd, check=True,
            stdout=subprocess.PIPE, stderr=subprocess.PIPE
        )
    except subprocess.CalledProcessError as e:
        # 失败时把 ffmpeg 报错和列表内容都写到 error.txt
        err_txt = ["❌ ffmpeg concat 失败",
                   f"命令: {' '.join(cmd)}",
                   "---- 列表内容 ----"]
        try:
            with open(list_file, "r", encoding="utf-8") as lf:
                err_txt.append(lf.read())
        except Exception as _:
            err_txt.append("(读取列表失败)")
        err_txt.append("---- ffmpeg stderr ----")
        err_txt.append(e.stderr.decode("utf-8", errors="ignore"))

        with open("error.txt", "w", encoding="utf-8") as ef:
            ef.write("\n".join(err_txt))

        raise RuntimeError("ffmpeg 拼接失败，详情见 error.txt") from e

    return out_path

# 在现有 concat_wavs_ffmpeg / to_mp3_ffmpeg 下面追加
def loudnorm_wav(in_wav: str, out_wav: str) -> str:
    import subprocess
    cmd = ["ffmpeg", "-y", "-i", in_wav, "-af", "loudnorm=I=-16:TP=-1.5:LRA=11", out_wav]
    subprocess.run(cmd, check=True)
    return out_wav


def to_mp3_ffmpeg(in_wav: str, out_mp3: str) -> str:
    cmd = ["ffmpeg", "-y", "-i", in_wav, "-codec:a", "libmp3lame", "-qscale:a", "2", out_mp3]
    try:
        subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    except subprocess.CalledProcessError as e:
        with open("error.txt", "w", encoding="utf-8") as ef:
            ef.write("❌ ffmpeg 转 mp3 失败\n")
            ef.write(f"命令: {' '.join(cmd)}\n")
            ef.write(e.stderr.decode("utf-8", errors="ignore"))
        raise RuntimeError("ffmpeg 转 mp3 失败，详情见 error.txt") from e
    return out_mp3
